// 目标：模拟缓冲区只允许同时存在一个商品，严格实现“一产一消”的节奏。
// 关键点：
//        使用布尔标志 hasItem 表示槽位状态。
//        生产者在 hasItem == true 时等待，消费者在 hasItem == false 时等待。
//        每次生产、消费后都使用 notify_all()，确保对方线程能从等待状态中苏醒。
//        通过循环调用 wait 的谓词形式，避免虚假唤醒导致的竞态。

    
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>

// 互斥锁保护以下共享状态
std::mutex mtx;

// 条件变量负责线程之间的通知
std::condition_variable cond;

// 单槽缓冲区只存一个整数
int currentItem = 0;

// 标记槽位是否已经装有商品
bool hasItem = false;

// 生产 / 消费的轮数，即每个线程要处理的商品个数
constexpr int kRounds = 10;

/**
 * 生产者线程：负责把商品放入单槽缓冲区
 */
void producer() {
    for (int i = 1; i <= kRounds; ++i) {
        std::unique_lock<std::mutex> lock(mtx);  // 加锁，保护共享状态

        // 当槽位已有商品时，生产者必须等待消费者取走
        cond.wait(lock, [] { return !hasItem; });

        // 槽位空闲，写入新商品
        currentItem = i;
        hasItem = true;

        std::cout << "[Producer] produced " << currentItem << '\n';

        // 通知消费者：槽位已填充
        cond.notify_all();
    }
}

/**
 * 消费者线程：负责从单槽缓冲区取出商品
 */
void consumer() {
    for (int i = 1; i <= kRounds; ++i) {
        std::unique_lock<std::mutex> lock(mtx);  // 加锁

        // 当槽位为空时，消费者等待生产者填充
        cond.wait(lock, [] { return hasItem; });

        // 槽位有商品，消费并清空槽位
        int item = currentItem;
        hasItem = false;

        std::cout << "    [Consumer] consumed " << item << '\n';

        // 通知生产者：槽位空闲，可继续生产
        cond.notify_all();
    }
}

int main() {
    // 分别启动生产者与消费者线程
    std::thread tProducer(producer);
    std::thread tConsumer(consumer);

    // 等待两个线程执行完所有轮次
    tProducer.join();
    tConsumer.join();

    std::cout << "Done.\n";
    return 0;
}